#region Using directives

using System;
//using System.Windows.Controls;
//using System.Windows.Media;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

#endregion

namespace mates_viz
{
    /// <summary>
    /// Manages the data received from the server and generates
    /// events that the Visualization should respond to
    /// </summary>
    class stateManager
    {

        private UIVizualization matesViz;   // Send update commands to this visualization
        private soapClient matesClient;     // instance of a web service client

        List<matesRelation> Relations = new List<matesRelation>();
        Dictionary<string, matesUser> Users = new Dictionary<string, matesUser>();
        Dictionary<int, matesLoc> Locations = new Dictionary<int, matesLoc>();

        // stores messages that are exchanges between users
        public Queue<message> msgQueue = new Queue<message>();

        // lists of my server-stored properties
        //public List<string> friendList = new List<string>();
        //public List<string> interestList = new List<string>();
        //public List<string> courseList = new List<string>();


		// Variables storing the currently logged-in user's state
		// ToDo: add logged in / out state variable
		private int myLocID; public int MyLocID { get { return myLocID; } } 
		private string myUserName;	public string MyUserName { get { return myUserName; } } 


        // Construct a new statemanager
        public stateManager(UIVizualization MatesVisualization, soapClient MatesClient)
        {
            matesViz = MatesVisualization;
            matesClient = MatesClient;
        }

        public void Update()
        {
			//TODO: turn this back on
			if (matesClient.sessionID != "")
			{
				matesClient.refresh(this);  // ask the client to update me
			}
        }

        public void InitializeLists()
        {
            //matesClient.getFriends(friendList);
            //matesClient.getInterests(interestList);
            //matesClient.getCourses(courseList);
        }

        // keeps track of which location the user is in.
        public void SetMyLocation(string username, int Loc_ID)
        {
			myLocID = Loc_ID; myUserName = username;
        }
        
        public void FlushUser(string Name)
        {
            // Remove a user and all relations that go along with that user
            foreach (matesRelation Rel in GetRelationsWithUser(Name))
                Relations.Remove(Rel);
            matesViz.RemoveUser(Name);
            Users.Remove(Name);
            
        }


        public void AddRelation(matesRelation Rel)
        {
            if (Relations.FindIndex(delegate(matesRelation rel) { return matesRelation.Equals(rel, Rel); }) != -1)
                Debug.WriteLine("Relation already exists!!");
            else
            {
                Relations.Add(Rel);
                //matesViz.HighlightUser(Rel.User);    // trigger the UI to show/update this user
            }

        }

        public void AddUser(matesUser User)
        {
            if (Users.ContainsKey(User.Name))
            {
                Debug.WriteLine("User " + User.Name + " already exists!  Replacing old user.");
                Users.Remove(User.Name);
            }
            Users.Add(User.Name, User);     // Add the new user to the dictionary
            matesViz.AddUser(User.Name);    // trigger the UI to show this user
        }

        public void AddLocation(matesLoc Location)
        {
            if (Locations.ContainsKey(Location.ID))
                Debug.WriteLine("Location " + Location.ID.ToString() + " already exists!!");
            else
            {
                Locations.Add(Location.ID, Location);   // Add the new user to the dictionary
                //matesViz.AddLocation(Location.ID);      // trigger the UI to show this new location
            }
        }

        public List<matesRelation> GetRelationsOfType(matesRelationType type)
        {
            // get all relations of the given type
            return Relations.FindAll(delegate(matesRelation rel) { return rel.Type == type; });
        }

        public matesUser GetUser(string user)
        {
            return (Users.ContainsKey(user)) ? Users[user] : null;
        }

        public matesLoc GetLocation(int locID)
        {
            return (Locations.ContainsKey(locID)) ? Locations[locID] : null;
        }

        public List<matesRelation> GetRelationsWithUser(string user)
        {
            // get all relations with a given user
            return Relations.FindAll(delegate(matesRelation rel) { return rel.User == user; });
        }

        public enum matesRelationType { Friend, Course, FriendOfFriend, Interest };

        public struct message
        {
            public string from;
            public string text;
            public string time;
        }

        public struct matesRelation
        {
            // type is the category
            matesRelationType type; public matesRelationType Type { get { return type; } }
            // user is the username of the user I am related to
            string user; public string User { get { return user; } }
            // subject of the relation is either a string like "EECS 492" or a username "jrpowers"
            string subject; public string Subject { get { return subject; } }

            // Construct a new relation
            public matesRelation(matesRelationType Type, string User, string Subject)
            { type = Type; user = User; subject = Subject; }

            public static bool Equals(matesRelation x, matesRelation y)
            {
                // two relations are equal if they are the same type, about the same user,
                // and have the same subject
               
                return ((x.Type == y.Type) && (x.User == y.User) && (x.Subject == y.Subject)) ? true : false;
            }
        }

        public class matesLoc
        {
            int id; public int ID { get { return id; } }                        // loc_id (unique)
            double lat; public double Latitude { get { return lat; } }          // latitude
            double lon; public double Longitude { get { return lon; } }         // longitude
            double bearing; public double Bearing { get { return bearing; } }   // bearing (in degrees)
            string name; public string Name { get { return name; } }            // loc name (not unique)
            double distance; public double Distance { get { return distance; } }// distance (in feet)

			// stores text and timestamp information associated with the location's wall.
			public struct wallinfo
			{
				string wallText; public string Text { get { return wallText; } }
				DateTime wallLastUpdateTs;
				public DateTime LastUpdateTs { get { return wallLastUpdateTs; } }
				public wallinfo(string Text, string LastUpdatedTs)
				{
					try { wallLastUpdateTs = Convert.ToDateTime(LastUpdatedTs); }
					catch { Error.Log("wallinfo: could not parse date/time string.");
					wallLastUpdateTs = DateTime.Now;}
					wallText = Text;
				}
			}
			wallinfo locWall; public wallinfo Wall { get { return locWall; } }	// location wall text

            // construct a new location (for transmission to server)
            public matesLoc(string Name, double Latitude, double Longitude)
            { name = Name; lat = Latitude; lon = Longitude; }

            // construct a new location (with all properties [ from server ] )
            public matesLoc(int ID, string Name, double Latitude, double Longitude, double Distance, double Bearing, string WallText)
            { id = ID; name = Name; distance = Distance; bearing = Bearing; lat = Latitude; lon = Longitude;
			  locWall = new wallinfo(WallText, DateTime.Now.ToString()); }

            // construct a new location (with some properties [ from server ] )
            public matesLoc(int ID, string Name, double Latitude, double Longitude)
            { id = ID; name = Name; lat = Latitude; lon = Longitude; }
        }

        public class matesUser
        {
            string name; public string Name { get { return name; } }    // username (unique)
            int loc_id; public int Loc_ID { get { return loc_id; } }    // user's location ID

            // construct a new user
            public matesUser(string Name, int Loc_ID)
            { name = Name; loc_id = Loc_ID; }
        }
    }

}